home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.08 Aug 90 / Test Object Source / CDigitalControl.c next >
Encoding:
C/C++ Source or Header  |  1989-12-31  |  9.5 KB  |  327 lines  |  [TEXT/KAHL]

  1. /*************************************************
  2.  CDigitalControl.c
  3.  
  4.                          The DigitalControl Class
  5.                          
  6.  This is NOT a Macintosh control with a CNTL
  7.  resource. It is a specialized sort of 'control'
  8.  with two buttons and a digital display, useful
  9.  for selecting a value when high precision and
  10.  interactive value display are needed. A variable-
  11.  speed mechanism allows for fast selection of the
  12.  desired value, while a tick-related delay control
  13.  keeps the reaction time independent from CPU
  14.  speed. 
  15.  
  16.  SUPERCLASS = CPane
  17.  
  18.  © 1989 Enrico Colombini. All rights reserved.
  19. *************************************************/
  20.  
  21. #include "CDigitalControl.h"
  22. #include <stdio.h>                    /*for sprintf*/
  23. #include <string.h>
  24.  
  25. /*************************************************
  26.  Class library globals accessed by CDigitalControl
  27. *************************************************/
  28.             /*the view the mouse went down into*/
  29. extern CView *gLastViewHit;    
  30.             /*event record of last mouse down*/
  31. extern EventRecord gLastMouseDown;    
  32.  
  33. /*************************************************
  34.  Toolbox-called local procedure, not part of the
  35.  CDigitalControl object 
  36. *************************************************/
  37. static pascal void Track(
  38.     ControlHandle macControl,short whichPart);
  39.  
  40. /*************************************************
  41.  IDigitalControl
  42.  
  43.  Initialize a CDigitalControl object. The
  44.  intialization is typical of an object descending
  45.  from the CView class. However, there is no rType
  46.  parameter and the resID parameter is used to load
  47.  four related object templates from the resource
  48.  fork: a Pane, a Button, a Border and a Static
  49.  Text. They must all have the same resID.
  50. *************************************************/
  51. void CDigitalControl::IDigitalControl(
  52.     short resID,            /*for Pane, btn, Bord, StTx*/
  53.     CView *anEnclosure,
  54.     CBureaucrat *aSupervisor)
  55. {
  56.     Rect r;
  57.  
  58.     inherited::IViewRes(        /*first, init main pane*/
  59.         'Pane',resID,anEnclosure,aSupervisor);
  60.  
  61.     dnBtn = new(CButton); /*create down button, « */
  62.     dnBtn->IButton(resID,this,this);
  63.     dnBtn->SetTitle((unsigned char *)"\p«");
  64.     dnBtn->SetActionProc(Track);    /*set re-entry*/
  65.     
  66.     GetFrame(&grayRect);    /*prepare gray rectangle*/
  67.     dnBtn->GetFrame(&r);
  68.     InsetRect(&grayRect,r.right,0);    /*between btns*/
  69.     
  70.     upBtn = new(CButton);    /*create up button, » */
  71.     upBtn->IButton(resID,this,this);
  72.     upBtn->Offset(grayRect.right,0,FALSE); /*align*/
  73.     upBtn->SetTitle((StringPtr)"\p»");
  74.     upBtn->SetActionProc(Track);    /*set re-entry*/
  75.     
  76.     border = new(CBorder);        /*create border*/
  77.     border->IViewRes('Bord',resID,this,this);
  78.     border->CenterWithinEnclosure(TRUE,TRUE);
  79.     
  80.     disp = new(CStaticText);    /*create display*/
  81.     disp->IViewRes('StTx',resID,border,this);
  82.     disp->FitToEnclosure(TRUE,TRUE); /*inside Bord*/
  83.     disp->SetFontName((StringPtr)"\pMonaco");
  84.     disp->SetFontSize(12);
  85.     disp->SetAlignment(teJustCenter);    /*center*/
  86.     
  87.     minValue = 0;                            /*set defaults*/
  88.     maxValue = 100;
  89.     SetValue(minValue);            /*set current value*/
  90.     stepSlow = 1;
  91.     stepFast = 5;
  92.     threshold = 20;
  93.     firstDelay = 18;                    /*300 msec*/
  94.     reptDelay = 6;                        /*100 msec*/
  95.     
  96.     lastDown = -1L;                        /*ensure difference*/
  97.     nextWhen = 0L;                        /*ensure acceptance*/
  98.     trackSpeed = trackCount = 0;    /*not tracking*/
  99.     
  100.     displayCmd = 0L;                    /*don't disturb boss*/
  101. }
  102.  
  103. /*************************************************
  104.  Draw {OVERRIDE}
  105.  
  106.  Draw the CDigitalControl object. Apart from the
  107.  gray rectangle between the two buttons, the
  108.  initialization is done automatically by the
  109.  methods inherited from the superclass(es). Note
  110.  that, as FillRect may move memory, it is unsafe
  111.  to pass the address of the instance variable
  112.  grayRect. Passing a local variable (r) is ok.
  113. *************************************************/
  114. void CDigitalControl::Draw(Rect *area)
  115. {
  116.     Rect r = grayRect;    /*FillRect may move mem!*/
  117.  
  118.     FillRect(&r,gray);
  119.     inherited::Draw(area);
  120. }
  121.  
  122. /************************************************
  123.  Track {NOT AN OBJECT METHOD - called by Toolbox}
  124.  
  125.  Called by Toolbox's TrackControl when the user
  126.  holds down the mouse button inside one of the
  127.  DigitalControl buttons. It can re-enter this
  128.  object by referring to the TCL global variable
  129.  gLastViewHit, which record the object the mouse
  130.  went down into (it). The supervisor of this
  131.  button is our DigitalControl object. The pointer
  132.  to (it) is passed to the TrackValue method to
  133.  tell it what button is currently pressed. After
  134.  the tracking, the drawing environment of the
  135.  original button must be restored for the Toolbox
  136.  to work properly.
  137. *************************************************/
  138. static pascal void    Track(
  139.     ControlHandle macControl, short whichPart)
  140. {
  141.     CView *it;
  142.     
  143.     it = gLastViewHit;        /*identify caller*/
  144.                                                 
  145.     ((CDigitalControl *)(it->itsSupervisor))
  146.         ->TrackValue(it);        /*Track!*/
  147.  
  148.     it->Prepare();                /*restore environment*/
  149. }
  150.  
  151. /*************************************************
  152.  TrackValue
  153.  
  154.  Called repeatedly (by way of pascal Track, above)
  155.  while the mousebutton is hold down inside one of
  156.  the DigitalControl buttons. The global variable
  157.  gLastMouseDown is used to differentiate the first
  158.  call after the mouse was pressed, to implement
  159.  the 3-speed step control of the value change.
  160. *************************************************/
  161. void CDigitalControl::TrackValue(CView *btn)
  162. {
  163.     short first;
  164.     short step;
  165.     short dir;
  166.     
  167.             /*check if 1st entry, exit if not yet time*/
  168.     first = (gLastMouseDown.when != lastDown);
  169.     if (! first && TickCount() < nextWhen)
  170.         return;
  171.         
  172.             /*if 1st entry: record time, set 1st delay*/
  173.     if (first) {
  174.         lastDown = gLastMouseDown.when;
  175.         nextWhen = TickCount()+firstDelay;
  176.         trackSpeed = 1;
  177.     } else {        /*not 1st entry, set repeat delay*/
  178.         nextWhen = TickCount()+reptDelay;
  179.          if (trackSpeed == 1) {                /*2nd speed*/
  180.              trackSpeed = 2;
  181.              trackCount = threshold-1;    /*countdown*/
  182.          } else {
  183.              if (--trackCount == 0) {        /*3rd speed*/
  184.                  trackSpeed = 3;
  185.              }
  186.          }
  187.     }
  188.     
  189.             /*choose step, reverse if down button*/
  190.     step = (trackSpeed < 3) ? stepSlow : stepFast;
  191.     if (btn == dnBtn)  step = -step;
  192.     
  193.     SetValue(value+step);        /*set display value*/
  194.     UpdateDisplayNow();            /*update immediately*/
  195. }
  196.  
  197. /*************************************************
  198.  SetValue
  199.  
  200.  Set current value, update display text in memory.
  201.  Screen update will happen at the next update
  202.  event. If no displayCmd has been set, a default
  203.  5-digit numerical display is used. If a
  204.  displayCmd has been set, a DoCommand message is
  205.  sent to the DigitalControl's supervisor. It may
  206.  set the text to display as it likes by means of
  207.  the SetDisplayText method.
  208. *************************************************/
  209. void CDigitalControl::SetValue(short val)
  210. {
  211.     char v[7];        /*display buffer*/
  212.     
  213.     value = val;        /*set new value, check it*/
  214.     if (value < minValue)  value = minValue;
  215.     if (value > maxValue)  value = maxValue;
  216.     
  217.     if (displayCmd == 0L) {        /*in-house display*/
  218.         sprintf(v,"%05d",value);    /*build disp. text*/
  219.         SetDisplayText(v);                /*set for display*/
  220.     } else {        /*ask boss to display as it pleases*/
  221.         itsSupervisor->DoCommand(displayCmd);
  222.     }
  223. }
  224.  
  225. /*************************************************
  226.  SetDisplayText
  227.  
  228.  Set the text to display. Called by SetValue,
  229.  directly or indirectly through the
  230.  DigitalControl's supervisor DoCommand method.
  231. *************************************************/
  232. void CDigitalControl::SetDisplayText(char *txt)
  233. {
  234.         /*update internal text*/
  235.     disp->SetTextPtr(txt,strlen(txt));
  236. }
  237.  
  238. /*************************************************
  239.  UpdateDisplayNow
  240.  
  241.  Update the text shown on the screen without
  242.  waiting for an update event. Used during the
  243.  tracking of one of the two buttons. Make sure
  244.  that the text won't be updated again when the
  245.  mouse button is released. A subclass of
  246.  DigitalControl may choose to update the display
  247.  faster by drawing the text directly using a
  248.  Tollbox call, thus also removing the slight
  249.  flicker during the update.
  250. *************************************************/
  251. void CDigitalControl::UpdateDisplayNow(void)
  252. {
  253.     Rect     r;
  254.     GrafPtr gp;
  255.  
  256.     disp->GetFrame(&r);            /*ready to draw*/
  257.     gp = disp->GetMacPort();
  258.  
  259.     BeginUpdate(gp);                    /*don't redraw later*/
  260.     disp->Prepare();                    /* but draw now*/
  261.     disp->Draw(&r);
  262.     EndUpdate(gp);
  263. }
  264.  
  265. /*************************************************
  266.  SetMinValue
  267.  
  268.  Set the minimum allowed value, check ≤ max.
  269. *************************************************/
  270. void CDigitalControl::SetMinValue(short val)
  271. {
  272.     minValue = val;
  273.     if (minValue > maxValue)  minValue = maxValue;
  274.     if (value < minValue)  SetValue(minValue);
  275. }
  276.  
  277. /*************************************************
  278.  SetMaxValue
  279.  
  280.  Set the maximum value allowed, check ≥ min.
  281. *************************************************/
  282. void CDigitalControl::SetMaxValue(short val)
  283. {
  284.     maxValue = val;
  285.     if (maxValue < minValue)  maxValue = minValue;
  286.     if (value > maxValue)   SetValue(maxValue);
  287. }
  288.  
  289. /*************************************************
  290.  SetSteps
  291.  
  292.  Set single & slow speed step, high speed step,
  293.  and number of steps before changing speed
  294.  (threshold).
  295. *************************************************/
  296. void CDigitalControl::SetSteps(
  297.     short slow, short fast, short thr)
  298. {
  299.     stepSlow = slow;
  300.     stepFast = fast;
  301.     threshold = thr;
  302. }
  303.  
  304. /*************************************************
  305.  SetDisplayCmd
  306.  
  307.  Set command number to send to supervisor while
  308.  tracking.
  309. *************************************************/
  310. void CDigitalControl::SetDisplayCmd(long cmd)
  311. {
  312.     displayCmd = cmd;            /*setup callback*/
  313.     SetValue(value);            /*boss, please update*/
  314. }
  315.  
  316. /*************************************************
  317.  GetValue
  318.  
  319.  Return current value: so this object does
  320.  something, after all!
  321. *************************************************/
  322. short CDigitalControl::GetValue(void)
  323. {
  324.     return value;
  325. }
  326.  
  327.